/**
 * Copyright 2019 吉鼎科技.

 * <p>
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * <p>
 * http://www.apache.org/licenses/LICENSE-2.0
 * <p>
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package cn.easyplatform.services.job;

import cn.easyplatform.cfg.EngineConfiguration;
import cn.easyplatform.contexts.Contexts;
import cn.easyplatform.contexts.EngineContext;
import cn.easyplatform.contexts.ExecuteContext;
import cn.easyplatform.dao.IdentityDao;
import cn.easyplatform.dos.EnvDo;
import cn.easyplatform.dos.UserDo;
import cn.easyplatform.entities.beans.LogicBean;
import cn.easyplatform.entities.beans.ResourceBean;
import cn.easyplatform.entities.helper.EventLogic;
import cn.easyplatform.interceptor.CommandContext;
import cn.easyplatform.lang.Strings;
import cn.easyplatform.log.LogManager;
import cn.easyplatform.services.IProjectService;
import cn.easyplatform.spi.engine.EngineFactory;
import cn.easyplatform.type.DeviceType;
import cn.easyplatform.type.IResponseMessage;
import cn.easyplatform.type.StateType;
import cn.easyplatform.util.MessageUtils;
import cn.easyplatform.util.RuntimeUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.shiro.SecurityUtils;
import org.quartz.*;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.Currency;
import java.util.Date;

/**
 * @author <a href="mailto:davidchen@epclouds.com">littleDog</a> <br/>
 * @since 2.0.0 <br/>
 */
@PersistJobDataAfterExecution
@DisallowConcurrentExecution
public class DefaultJobWorker implements Job {

    private static final Logger log = LoggerFactory.getLogger(DefaultJobWorker.class);

    @SuppressWarnings("unchecked")
    @Override
    public void execute(JobExecutionContext ctx) throws JobExecutionException {
        EngineContext ec = (EngineContext) EngineFactory.me();
        EngineConfiguration engineConfiguration = ec.getEngineConfiguration();
        JobDataMap dm = ctx.getJobDetail().getJobDataMap();
        IProjectService ps = (IProjectService) engineConfiguration.getService(ctx.getJobDetail().getKey().getGroup());
        ResourceBean job = (ResourceBean) dm.get("job");
        String taskId = job.getProps().get("task");
        if (log.isDebugEnabled())
            log.debug("start job {} {}", job.getId(), job.getName());
        CommandContext cc = new CommandContext(engineConfiguration);
        UserDo userInfo = null;
        try {
            Contexts.set(CommandContext.class, cc);
            cc.setupEnv(new EnvDo(ps.getId(),
                    DeviceType.JOB, ps
                    .getLanguages().get(0), null, null));
            if (!Strings.isBlank(job.getProps().get("user"))) {
                IdentityDao dao = cc.getIdentityDao(true);
                userInfo = dao.getUser(cc.getProjectService().getConfig()
                        .getAuthenticationQuery(), job.getProps().get("user"));
            }
            if (userInfo == null) {
                userInfo = new UserDo();
                userInfo.setId("job-" + job.getId());
                userInfo.setName(job.getName());
            }
            userInfo.setDeviceType(DeviceType.JOB);
            userInfo.setState(StateType.START);
            userInfo.setIp("localhost");
            userInfo.setLocale(cc.getEnv().getLocale());
            if (!Strings.isBlank(job.getProps().get("org"))) {
                userInfo.setOrg(cc.getIdentityDao(false).getUserOrg(
                        cc.getProjectService().getConfig().getUnitQuery(),
                        job.getProps().get("org")));
            }
            cc.setUser(userInfo);
            String checkHoliday = job.getProps().get("checkHoliday");
            if (Strings.isBlank(checkHoliday))
                checkHoliday = "false";
            if (checkHoliday.equalsIgnoreCase("false")
                    || (checkHoliday.equalsIgnoreCase("true") && ps
                    .getBusinessDateHandler(cc).isBusinessDate(
                            new Date(),
                            Currency.getInstance(ps.getLocale())
                                    .getCurrencyCode()))) {
                //设置会话永不过期
                //SecurityUtils.getSubject().getSession().setTimeout(-1);
                LogManager.startUser(engineConfiguration.getLogPath(), ps.getId(), userInfo);
                LogManager.beginRequest(ps.getId(), userInfo);
                IResponseMessage<?> resp = engineConfiguration.getTaskExecuter(cc).execute(new ExecuteContext(cc, taskId));
                if (!resp.isSuccess()) {
                    if (log.isInfoEnabled())
                        log.error("execute job {} error:{}", resp.getCode(), resp.getBody());
                }
            }
        } catch (Exception ex) {
            if (log.isErrorEnabled())
                log.error("execute job {} error:{}", job.getId(), MessageUtils
                        .getMessage(ex, log).getBody());
        } finally {
            try {
                String logicId = job.getProps().get("onAfter");
                if (!StringUtils.isBlank(logicId) && cc.getWorkflowContext() != null && cc.getWorkflowContext().getRecord() != null) {
                    LogicBean lb = cc.getEntity(logicId);
                    if (lb != null) {
                        EventLogic el = new EventLogic();
                        el.setId(lb.getId());
                        el.setContent(lb.getContent().trim());
                        RuntimeUtils.eval(cc, el, cc.getWorkflowContext().getRecord());
                    }
                }
            } catch (Exception e) {
                if (log.isErrorEnabled())
                    log.error("run job {}", job.getId(), e);
            }
            SecurityUtils.getSubject().logout();
            Contexts.clear();
            LogManager.stopUser(userInfo);
        }
    }
}
